package crmdna.gspreadsheet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;

import crmdna.common.APIException;
import crmdna.common.APIResponse.Status;

public class GSpreadSheet {

	final static int MAX_LINES = 25000;

	public static List<Map<String, String>> getPublishedSpreasheetAsListOfMap(
			String gsKey, Integer maxLines) throws IOException {
		if (maxLines == null)
			maxLines = 2500;

		if (maxLines > MAX_LINES)
			throw new APIException(Status.ERROR_RESOURCE_INCORRECT,
					"Max lines [" + maxLines + "] cannot be greater than ["
							+ MAX_LINES + "]");

		String jsonFeedURL = getJSONFeedURL(gsKey);

		String json = getJSON(jsonFeedURL);

		List<Map<String, String>> listOfMap = getListOfMap(json, maxLines);

		return listOfMap;
	}

	static List<Map<String, String>> getListOfMap(String json, int maxLines) {

		Set<String> keysToIgnore = new HashSet<>();
		keysToIgnore.add("id");
		keysToIgnore.add("updated");
		keysToIgnore.add("category");
		keysToIgnore.add("title");
		keysToIgnore.add("content");
		keysToIgnore.add("link");

		JsonParser parser = new JsonParser();

		JsonObject jsonObject;

		try {
			jsonObject = parser.parse(json).getAsJsonObject()
					.getAsJsonObject("feed");
		} catch (JsonSyntaxException jse) {
			throw new APIException(
					Status.ERROR_RESOURCE_INCORRECT,
					"Unable to read spreadsheet data. "
							+ "Please check spreadhsheet key is valid and the spreadsheet is published");
		}

		if (null == jsonObject) {
			throw new APIException(Status.ERROR_RESOURCE_INCORRECT,
					"Invalid json. Cannot find element [feed]");
		}

		JsonArray rows = jsonObject.getAsJsonArray("entry");

		System.out.println("No of rows: " + rows.size());

		List<Map<String, String>> list = new ArrayList<>();

		int lineNo = 0;
		for (JsonElement row : rows) {
			lineNo++;

			if (lineNo > maxLines)
				throw new APIException(
						Status.ERROR_RESOURCE_INCORRECT,
						"Google spreadsheet has more number of rows than specified maximum of ["
								+ maxLines
								+ "]. Try specifying a larger number (but should be lesser than "
								+ MAX_LINES + ")");

			jsonObject = (JsonObject) row;

			Map<String, String> map = new HashMap<>();
			list.add(map);

			for (Entry<String, JsonElement> element : jsonObject.entrySet()) {

				String key = element.getKey();
				if (keysToIgnore.contains(key))
					continue;

				if (!key.startsWith("gsx$"))
					throw new APIException(
							Status.ERROR_RESOURCE_INCORRECT,
							"Invalid column header key ["
									+ key
									+ "]. Key for column header should start with gsx$");

				key = key.substring(4);

				String value = ((JsonObject) element.getValue()).get("$t")
						.getAsString();

				map.put(key, value);
			}
		}

		return list;
	}

	static String getJSON(String jsonFeedURL) throws IOException {

		URL url = new URL(jsonFeedURL);

		StringBuilder builder = new StringBuilder();

		try (InputStreamReader inputStreamReader = new InputStreamReader(
				url.openStream())) {
			try (BufferedReader bufferedReader = new BufferedReader(
					inputStreamReader)) {

				String line;

				while ((line = bufferedReader.readLine()) != null) {
					builder.append(line);
				}
			}
		}

		return builder.toString();
	}

	static String getJSONFeedURL(String gsKey) {
		return "https://spreadsheets.google.com/feeds/list/" + gsKey
				+ "/od6/public/values?alt=json";
	}
}
